﻿using PSE.Framework.Communication.Configuration.Adapters.File.FlatFile;
using PSE.Framework.Communication.Adapters.File;
using System.IO;
using PSE.Framework.Communication.Configuration.Adapters;
using System.Collections.Generic;
using FileHelpers;
using System;
using PSE.Framework.Communication.Configuration.File;
using PSE.Framework.Communication.Configuration.File.FlatFile;
using System.Text;
namespace PSE.Framework.Communication.Adapters.File.FlatFile
{
    public class AsyncFlatFileInputAdapter : AsyncFileInputAdapter<FlatFileInputConfiguration>
    {
        #region Propriedades de controle
        /// <summary>
        /// caminho completo do arquivos
        /// </summary>
        private string _fullPath;

        /// <summary>
        /// Objeto de leitura do arquivos
        /// </summary>
        private StreamReader _fileReader = null;

        /// <summary>
        /// Numero de linhas do arquivo
        /// </summary>
        private int? _rowCount = 0;

        /// <summary>
        /// Dicionario contendo os objetos de traducao de registros
        /// a chave do dicionario sera uma action e o objeto armazenado sera criado de acordo com as
        /// configuracoes informadas na action
        /// </summary>
        private Dictionary<string, ActionDeserializerInfo> _recordInfos;

        #endregion

        public AsyncFlatFileInputAdapter()
        {
            _recordInfos = new Dictionary<string, ActionDeserializerInfo>();
        }

        public override void Open(FlatFileInputConfiguration config, object parameter)
        {
            base.Open(config, parameter);

            //recuperar as actions e criar os recordinfos para transformacao dos registros
            bool fixedType = false;
            Type recordType;
            FileHelpers.RecordInfo recordInfo;

            //varrer as actions e criar os recordInfo
            foreach (FlatFileInputAdapterActionConfiguration action in this.Configuration.Actions)
            {
                //se ja existe uma configuracao para a action
                if (_recordInfos.ContainsKey(action.Name))
                    continue;

                //se informou uma classe com o formato
                if (action.DeserializedMessageType != null)
                {
                    fixedType = true;
                    recordType = action.DeserializedMessageType;
                    recordInfo = new FileHelpers.RecordInfo(recordType);
                }
                //se informou um arquivo com o formato
                else if (action.DeserializedMessageFile != null)
                {
                    fixedType = false;
                    recordType = FileHelpers.RunTime.ClassBuilder.ClassFromXmlFile(action.DeserializedMessageFile);
                    recordInfo = new FileHelpers.RecordInfo(recordType);
                }
                //se nao informou um formato, retornar registro bruto
                else
                {
                    fixedType = false;
                    recordInfo = null;
                }

                ActionDeserializerInfo adi = new ActionDeserializerInfo(fixedType, recordInfo);
                _recordInfos.Add(action.Name, adi);
            }

        }

        protected override void OpenFile(string fullPath)
        {
            _fullPath = fullPath;
            _fileReader = new StreamReader(fullPath, Encoding.Default);
        }

        protected override object ReadRecord()
        {
            string line = _fileReader.ReadLine();

            // Não le linhas em branco
            if (string.IsNullOrEmpty(line))
                return null;
            else if (line.Replace(Environment.NewLine, "").Length == 0)
                return null;
            else
                return line;
        }

        protected override object Deserialize(object message, string action)
        {
            ActionDeserializerInfo adi = _recordInfos[action];
            //se foi configurada uma forma de transformar o dados bruto em objeto, transformar e retornar
            if (adi.RecordInfo != null)
            {
                //se foi informado um tipo fixo com a formatacao
                if (adi.IsFixedType)
                {
                    return adi.RecordInfo.StringToRecord((string)message);
                }
                //se foi informado um arquivo com a formatacao
                else
                {
                    return adi.RecordInfo.StringToDictionary((string)message);
                }
            }
            //se nao foi configurada uma forma de transformar o dado bruto em um objeto, retornar o dado bruto
            else
            {
                return message;
            }
            //de acordo com a action recuperar o record info

        }

        protected override void CloseFile()
        {
            _fileReader.Close();
            _fileReader.Dispose();
        }

        protected override int GetFileRowCount()
        {
            using (StreamReader countReader = new StreamReader(_fullPath, Encoding.Default))
            {
                if (_rowCount != null)
                {
                    _rowCount = 0;
                    while (!countReader.EndOfStream)
                    {
                        string line = countReader.ReadLine();

                        // Não conta linhas em branco
                        if (!string.IsNullOrEmpty(line) &&
                            line.Replace(Environment.NewLine, "").Length != 0)
                            _rowCount++;
                    }
                }
                countReader.Close();
            }

            return _rowCount.GetValueOrDefault();
        }
    }//end FlatFileInputAdapter

}